package controllers

import java.io.File
import dao._
import implicits.Implicits._

import javax.inject.Inject
import models.Tables._
import org.joda.time.DateTime
import play.api.i18n.I18nSupport
import play.api.mvc._
import shared.Pojo._
import shared.VarTool
import tool.{FileTool, FormTool, MatrixFileTool, Tool, VarInfoFileTool}
import utils.Utils

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import upickle.default._

/**
 * Created by yz on 23/7/2020
 */
class VarInfoFileDataController @Inject()(cc: ControllerComponents)(
  implicit val modeDao: ModeDao,
  implicit val missionDao: MissionDao,
  implicit val varInfoFileDataDao: VarInfoFileDataDao,

) extends AbstractController(cc) with VarInfoFileTool with I18nSupport {

  def getAll = Action.async { implicit request =>
    val userId = Tool.getUserId
    val fileNameOp = FormTool.fileNameOpForm.bindFromRequest().get.fileName
    val f = fileNameOp.map { fileName =>
      val metabolitesF = Tool.produceRawDataLinesF(userId, fileName).map { lines =>
        lines.map(_.head).drop(1)
      }
      metabolitesF.flatMap { metabolites =>
        val columnNumLeastOp = FormTool.columnNumLeastOpForm.bindFromRequest().get.columnNumLeast
        columnNumLeastOp.map { columnNumLeast =>
          varInfoFileDataDao.selectAll(userId, metabolites, columnNumLeast)
        }.getOrElse {
          varInfoFileDataDao.selectAll(userId, metabolites)
        }
      }
    }.getOrElse {
      varInfoFileDataDao.selectAll(userId)
    }
    f.map { x =>
      varInfoFileDataDao.selectAll(userId).map { x =>
        val fileNames = x.map(x => s"${x.fileName}")
        val kindDir = getUserDataKindDir(userId)
        kindDir.listFiles().filter {
          file =>
            !fileNames.contains(file.getName)
        }.foreach(_.deleteQuietly)
      }
      val array = Utils.getArrayByTs(x)
      Ok(writeJs(array))
    }
  }

  def add = Action.async(parse.multipartFormData) {
    implicit request =>
      val data = FormTool.metDataAddForm.bindFromRequest().get
      val tmpDir = Tool.createTempDirectory("tmpDir")
      val userId = Tool.getUserId
      val file = Tool.getInitFile(data, tmpDir, VarInfoDataKind.defaultFileName)
      val myMessage = FileTool.listFileCheck(file).toMyMessage
      if (!myMessage.valid) {
        Tool.deleteDirectory(tmpDir)
        Future.successful(Ok(ujson.Obj("message" -> myMessage.message, "valid" -> false)))
      } else {
        varInfoFileDataDao.selectAllFileName(userId).flatMap {
          fileNames =>
            val newFileName = Tool.getNewFileName(fileNames, file)
            val kindDir = getUserDataKindDir(userId)
            val newFile = new File(kindDir, s"${
              newFileName
            }")
            val lines = file.txtLines.notAnnoLines
            val columnNum = lines.head.size
            lines.toTxtFile(newFile)
            val metabolites = newFile.txtLines.map(_.head).tail
            val row = VarInfoFileDataRow(id = 0, fileName = s"${newFileName}", userId = userId, tags = data.tags,
              comment = data.comment, uploadTime = new DateTime(), size = file.size.toInt, metabolites = metabolites,
              columnNum =columnNum)
            varInfoFileDataDao.insert(row)
        }.map {
          x =>
            Tool.deleteDirectory(tmpDir)
            Ok(ujson.Obj("valid" -> true))
        }
      }
  }

  def deletes = Action.async {
    implicit request =>
      val userId = Tool.getUserId
      val data = FormTool.idsForm.bindFromRequest().get
      varInfoFileDataDao.selectAll(data.ids).flatMap { rows =>
        Future {
          rows.foreach { row =>
            val file = getUserDataKindFile(row.userId, row.fileName)
            file.deleteQuietly
          }
        }
        varInfoFileDataDao.deletes(userId, data.ids).map { x =>
          Ok(writeJs("success"))
        }
      }
  }

  def update = Action.async { implicit request =>
    val id = FormTool.idForm.bindFromRequest().get.id
    val data = FormTool.updateForm.bindFromRequest().get
    varInfoFileDataDao.select(id).flatMap { row =>
      val newRow = row.copy(fileName = data.fileName.addSuffix, tags = data.tags, comment = data.comment)
      val kindDir = getUserDataKindDir(row.userId)
      val newFile = new File(kindDir, s"${data.fileName.addSuffix}")
      new File(kindDir, row.fileName).renameTo(newFile)
      varInfoFileDataDao.update(newRow).map { x =>
        Ok(writeJs("success"))
      }
    }
  }

  def downloadFileById = Action.async {
    implicit request =>
      val data = FormTool.idForm.bindFromRequest().get
      varInfoFileDataDao.select(data.id).map {
        row =>
          val file = getUserDataKindFile(row.userId, row.fileName)
          Ok.sendFile(file).withHeaders(
            CONTENT_DISPOSITION -> Tool.getContentDisposition(s"${
              file.getName
            }"),
            CONTENT_TYPE -> "application/x-download"
          )
      }
  }

  def getFileDataById = Action.async {
    implicit request =>
      val data = FormTool.idForm.bindFromRequest().get
      varInfoFileDataDao.select(data.id).map {
        x =>
          val json = writeJs(x).toObj ++ ujson.Obj("kind" -> VarInfoDataKind.name)
          Ok(json)
      }
  }

  def getFileData = Action.async { implicit request =>
    val softKindOp = FormTool.softKindOpForm.bindFromRequest().get.softKind
    val fileF = softKindOp.map { softKind =>
      Future {
        val fileName = FormTool.fileNameForm.bindFromRequest().get.fileName
        val dir = new File(Tool.softExampleDir, softKind)
        new File(dir, fileName)
      }
    }.getOrElse {
      val data = FormTool.idForm.bindFromRequest().get
      varInfoFileDataDao.select(data.id).map { row =>
        getUserDataKindFile(row.userId, row.fileName)
      }
    }
    fileF.map { file =>
      val (columnNames, array) = Utils.getInfoByLines(file.txtLines)
      val json = ujson.Obj("columnNames" -> columnNames, "array" -> array)
      Ok(json)
    }
  }

  def detailBefore = Action.async {
    implicit request =>
      val idData = FormTool.idOpForm.bindFromRequest().get
      val userId = Tool.getUserId
      idData.id.map {
        x =>
          Future {
            Ok(views.html.user.data.varInfoDetail(x))
          }
      }.getOrElse {
        val data = FormTool.fileNameForm.bindFromRequest().get
        val fileName = data.fileName
        val names = fileName.split("/")
        val kind = VarTool.showDirNameMap(names(0)).name
        varInfoFileDataDao.select(userId, names(1)).map(_.id).map {
          x =>
            Ok(views.html.user.data.varInfoDetail(x))
        }
      }
  }

  def fileNameNonExistCheck = Action.async {
    implicit request =>
      val data = FormTool.fileNameForm.bindFromRequest.get
      val originalFileNameOp = FormTool.originalFileNameOpForm.bindFromRequest().get.originalFileName
      val userId = Tool.getUserId
      val fileName = data.fileName.addSuffix
      varInfoFileDataDao.selectAllFileName(userId).map { fileNames =>
        val valid = originalFileNameOp.map { originalFileName =>
          if (originalFileName == data.fileName) {
            true
          } else {
            !fileNames.contains(fileName)
          }
        }.getOrElse {
          !fileNames.contains(fileName)
        }
        Ok(ujson.Obj("valid" -> valid))
      }
  }


}
